/** ===========================================================================
* @file net_config.c
*
* @path $(IPNCPATH)\sys_server\src\
*
* @desc
* .
* Copyright (c) Appro Photoelectron Inc.  2008
*
* Use of this software is controlled by the terms and conditions found
* in the license agreement under which this software has been supplied
*
* =========================================================================== */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <unistd.h>
#include <signal.h>
#include <asm/types.h>
#include <linux/sockios.h>
//#include <asm/arch/v4l_ioctl.h>
#include "userLog.h"
//#include "lancam.h"
#include "net_config.h"

/***************************************************************************
 *                                                                         *
 ***************************************************************************/
static struct sockaddr_in sa = {
	sin_family : PF_INET,
	sin_port : 0
};
/**
* @brief Mii data.
*/
struct mii_data
{
	unsigned short phy_id;
	unsigned short reg_num;
	unsigned short val_in;
	unsigned short val_out;
};

/**
 * @brief	Set a certain interface flag.
 * @param	"char *ifname" : interface name
 * @param	"short flag" : flag
 * @retval	0 : success ; -1 : fail
 */
int net_set_flag(char *ifname, short flag)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
	{
		LOG_ERROR("net_set_flag: ioctl SIOCGIFFLAGS: %s", strerror(errno));
		close(skfd);
		return (-1);
	}
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	ifr.ifr_flags |= flag;
	if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0)
	{
		LOG_ERROR("net_set_flag: ioctl SIOCSIFFLAGS: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);
	return (0);
}

/**
 * @brief	Clear a certain interface flag.
 * @param	"char *ifname" : interface name
 * @param	"short flag" : flag
 * @retval	0 : success ; -1 : fail
 */
int net_clr_flag(char *ifname, short flag)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
	{
		LOG_ERROR("net_clr_flag: ioctl SIOCGIFFLAGS: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	ifr.ifr_flags &= ~flag;
	if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0)
	{
		LOG_ERROR("net_clr_flag: ioctl SIOCSIFFLAGS: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);
	return (0);
}

/**
 * @brief	Get an interface flag.
 * @param	"char *ifname" : interface name
 * @retval	ifr.ifr_flags
 * @retval	-1 : fail
 */
int net_get_flag(char *ifname)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
	{
		LOG_ERROR("net_get_flag: ioctl SIOCGIFFLAGS: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);
	return ifr.ifr_flags;
}

/**
 * @brief	Set an interface up & running
 * @param	"char *ifname" : interface name
 * @retval	0 : success ; -1 : fail
 */
int net_nic_up(char *ifname)
{
	return net_set_flag(ifname, (IFF_UP | IFF_RUNNING));
}

/**
 * @brief	Set an interface down
 * @param	"char *ifname" : interface name
 * @retval	0 : success ; -1 : fail
 */
int net_nic_down(char *ifname)
{
	return net_clr_flag(ifname, IFF_UP);
}

/**
 * @brief	get address of an interface
 * @param	"char *ifname" : interface name
 * @retval	net address
 */
in_addr_t net_get_ifaddr(char *ifname)
{
	struct ifreq ifr;
	int skfd;
	struct sockaddr_in *saddr;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}

	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0)
	{
		LOG_ERROR("net_get_ifaddr: ioctl SIOCGIFADDR: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);

	saddr = (struct sockaddr_in *)&ifr.ifr_addr;
	return saddr->sin_addr.s_addr;
}

int net_get_ifaddr_a(char *ifname, char *addr)
{
	in_addr_t in_addr;
	char *pAddr = NULL;

	if (ifname == NULL || addr == NULL)
	{
		LOG_INFO("net_get_ifaddr_a() invalid arguments");
		return -1;
	}

	in_addr = net_get_ifaddr(ifname);
	pAddr = inet_ntoa(*(struct in_addr *)&in_addr);
	if (pAddr == NULL)
	{
		LOG_INFO("net_get_ifaddr_a() inet_ntoa() error");
		return -1;
	}
	strcpy(addr, pAddr);

	return 0;
}

/**
 * @brief	get ip of an interface
 * @param	"int skfd" :
 * @param	"char *ifname" : interface name
 * @retval	ip
 */
struct in_addr net_get_ip(int skfd, char *ifname)
{
	struct ifreq ifr;

	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0)
	{
		LOG_ERROR("net_get_ip: ioctl SIOCGIFADDR: %s", strerror(errno));
		return (struct in_addr){-1};
	}
	return ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
}

/**
 * @brief	set ip of an interface
 * @param	"char *ifname" : interface name
 * @param	"in_addr_t addr" : ip address
 * @retval	0 : success ; -1 : fail
 */
int net_set_ifaddr(char *ifname, in_addr_t addr)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	sa.sin_addr.s_addr = addr;
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	memcpy((char *)&ifr.ifr_addr, (char *)&sa, sizeof(struct sockaddr));
	if (ioctl(skfd, SIOCSIFADDR, &ifr) < 0)
	{
		LOG_ERROR("net_set_ifaddr: ioctl SIOCSIFADDR: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);
	return 0;
}

int net_set_ifaddr_a(char *ifname, char *addr)
{
	in_addr_t in_addr;

	if (ifname == NULL || addr == NULL)
	{
		LOG_INFO("net_set_ifaddr_a() invalid arguments");
		return -1;
	}

	in_addr = inet_addr(addr);

	return net_set_ifaddr(ifname, in_addr);
}

/**
 * @brief	get address of an interface
 * @param	"char *ifname" : interface name
 * @retval	address
 */
in_addr_t net_get_netmask(char *ifname)
{
	struct ifreq ifr;
	int skfd;
	struct sockaddr_in *saddr;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}

	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0)
	{
		LOG_ERROR("net_get_netmask: ioctl SIOCGIFNETMASK in sysserver: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);

	saddr = (struct sockaddr_in *)&ifr.ifr_addr;
	return saddr->sin_addr.s_addr;
}

int net_get_netmask_a(char *ifname, char *addr)
{

	in_addr_t in_addr;
	char *pAddr = NULL;

	if (ifname == NULL || addr == NULL)
	{
		LOG_INFO("net_get_netmask_a() invalid arguments");
		return -1;
	}

	in_addr = net_get_netmask(ifname);
	pAddr = inet_ntoa(*(struct in_addr *)&in_addr);
	if (pAddr == NULL)
	{
		LOG_INFO("net_get_netmask_a() inet_ntoa() error");
		return -1;
	}
	strcpy(addr, pAddr);

	return 0;
}

/**
 * @brief	get netmask of an interface
 * @param	"char *ifname" : [IN]interface name
 * @param	"in_addr_t addr" : [OUT]netmask
 * @retval	0 : success ; -1 : fail
 */
int net_set_netmask(char *ifname, in_addr_t addr)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	sa.sin_addr.s_addr = addr;
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	memcpy((char *)&ifr.ifr_addr, (char *)&sa, sizeof(struct sockaddr));
	if (ioctl(skfd, SIOCSIFNETMASK, &ifr) < 0)
	{
		LOG_ERROR("net_set_netmask: ioctl SIOCSIFNETMASK: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);
	return 0;
}

int net_set_netmask_a(char *ifname, char *addr)
{
	in_addr_t in_addr;

	if (ifname == NULL || addr == NULL)
	{
		LOG_INFO("net_set_netmask_a() invalid arguments");
		return -1;
	}

	in_addr = inet_addr(addr);

	return net_set_netmask(ifname, in_addr);
}

/**
 * @brief	get mac address of an interface
 * @param	"char *ifname" : [IN]interface name
 * @param	"unsigned char *mac" : [OUT]mac address
 * @retval	0 : success ; -1 : fail
 */
int net_get_hwaddr(char *ifname, unsigned char *mac)
{
	struct ifreq ifr;
	int skfd;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}

	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
	{
		LOG_ERROR("net_get_hwaddr: ioctl SIOCGIFHWADDR: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	close(skfd);

	memcpy(mac, ifr.ifr_ifru.ifru_hwaddr.sa_data, IFHWADDRLEN);
	return 0;
}

int net_set_hwaddr(char *ifname, unsigned char *mac)
{
	unsigned char mac1[6], mac2[18];
	int skfd, rtn;
	struct ifreq ifr;
	if (!ifname || !mac)
	{
		return -1;
	}
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	ifr.ifr_addr.sa_family = AF_LOCAL;
	strncpy(ifr.ifr_name, (const char *)ifname, IFNAMSIZ);
	memcpy((unsigned char *)ifr.ifr_hwaddr.sa_data, mac, 6);
	if ((rtn = ioctl(skfd, SIOCSIFHWADDR, &ifr)) != 0)
	{
		perror("SIOCSIFHWADDR");
	}
	close(skfd);
	return rtn;
}
/**
 * @brief	add a gateway
 * @param	"in_addr_t addr" : [IN]address of gateway
 * @retval	0 : success ; -1 : fail
 */
int net_add_gateway(char *dev, in_addr_t addr)
{
	struct rtentry rt;
	int skfd;

	/* Clean out the RTREQ structure. */
	memset((char *)&rt, 0, sizeof(struct rtentry));

	/* Fill in the other fields. */
	rt.rt_flags = (RTF_UP | RTF_GATEWAY);

	rt.rt_dst.sa_family = PF_INET;
	rt.rt_genmask.sa_family = PF_INET;

	sa.sin_addr.s_addr = addr;
	memcpy((char *)&rt.rt_gateway, (char *)&sa, sizeof(struct sockaddr));

	rt.rt_dev = dev;

	/* Create a socket to the INET kernel. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	/* Tell the kernel to accept this route. */
	if (ioctl(skfd, SIOCADDRT, &rt) < 0)
	{
		LOG_ERROR("net_add_gateway: ioctl SIOCADDRT: %s", strerror(errno));
		LOG_INFO("net_add_gateway dev=%s,addr=%08x", dev, addr);
		close(skfd);
		return -1;
	}
	/* Close the socket. */
	close(skfd);
	return (0);
}

/**
 * @brief	delete a gateway
 * @param	"in_addr_t addr" : [IN]address of gateway
 * @retval	0 : success ; -1 : fail
 */
int net_del_gateway(char *dev, in_addr_t addr)
{
	struct rtentry rt;
	int skfd;

	/* Clean out the RTREQ structure. */
	memset((char *)&rt, 0, sizeof(struct rtentry));

	/* Fill in the other fields. */
	rt.rt_flags = (RTF_UP | RTF_GATEWAY);

	rt.rt_dst.sa_family = PF_INET;
	rt.rt_genmask.sa_family = PF_INET;

	sa.sin_addr.s_addr = addr;
	memcpy((char *)&rt.rt_gateway, (char *)&sa, sizeof(struct sockaddr));

	rt.rt_dev = dev;

	/* Create a socket to the INET kernel. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	/* Tell the kernel to accept this route. */
	if (ioctl(skfd, SIOCDELRT, &rt) < 0)
	{
		LOG_ERROR("net_del_gateway: ioctl SIOCDELRT: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	/* Close the socket. */
	close(skfd);
	return (0);
}

int net_del_router(char *dev, in_addr_t addr, in_addr_t mask)
{
	struct rtentry rt;
	int skfd;

	/* Clean out the RTREQ structure. */
	memset((char *)&rt, 0, sizeof(struct rtentry));

	/* Fill in the other fields. */
	rt.rt_flags = (RTF_UP);

	rt.rt_dst.sa_family = PF_INET;
	rt.rt_genmask.sa_family = PF_INET;

	sa.sin_family = PF_INET;
	sa.sin_addr.s_addr = addr;
	memcpy((char *)&rt.rt_dst, (char *)&sa, sizeof(struct sockaddr));
	sa.sin_family = PF_INET;
	sa.sin_addr.s_addr = mask;
	memcpy((char *)&rt.rt_genmask, (char *)&sa, sizeof(struct sockaddr));

	rt.rt_dev = dev;

	/* Create a socket to the INET kernel. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	/* Tell the kernel to accept this route. */
	if (ioctl(skfd, SIOCDELRT, &rt) < 0)
	{
		LOG_ERROR("net_del_router: ioctl SIOCDELRT: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	/* Close the socket. */
	close(skfd);
	return (0);
}

int net_add_router(char *dev, in_addr_t addr, in_addr_t mask)
{
	struct rtentry rt;
	int skfd;

	/* Clean out the RTREQ structure. */
	memset((char *)&rt, 0, sizeof(struct rtentry));

	/* Fill in the other fields. */
	rt.rt_flags = (RTF_UP);

	rt.rt_dst.sa_family = PF_INET;
	rt.rt_genmask.sa_family = PF_INET;

	sa.sin_family = PF_INET;
	sa.sin_addr.s_addr = addr;
	memcpy((char *)&rt.rt_dst, (char *)&sa, sizeof(struct sockaddr));
	sa.sin_family = PF_INET;
	sa.sin_addr.s_addr = mask;
	memcpy((char *)&rt.rt_genmask, (char *)&sa, sizeof(struct sockaddr));

	rt.rt_dev = dev;

	/* Create a socket to the INET kernel. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error: %s", strerror(errno));
		return -1;
	}
	/* Tell the kernel to accept this route. */
	if (ioctl(skfd, SIOCADDRT, &rt) < 0)
	{
		LOG_ERROR("net_del_router: ioctl SIOCDELRT: %s", strerror(errno));
		close(skfd);
		return -1;
	}
	/* Close the socket. */
	close(skfd);
	return (0);
}

/**
 * @brief	set domain name server.
 * @param	"char *dnsname" : [IN]dns name
 * @retval	0 : success ; -1 : fail
 */
int net_set_dns(char *dnsname)
{
	FILE *fp;

	fp = fopen(RESOLV_CONF, "w");
	if (fp)
	{
		fprintf(fp, "nameserver %s\n", dnsname);
		fclose(fp);
		LOG_INFO("dns=%s", dnsname);
		return 0;
	}
	LOG_INFO("net_set_dns: file \"%s\" opened for writing error!", RESOLV_CONF);
	return -1;
}

/**
 * @brief	get domain name server.
 * @param	none
 * @retval	dns address
 */
in_addr_t net_get_dns(void)
{
	FILE *fp;
	char dnsname[80];

	fp = fopen(RESOLV_CONF, "r");
	if (fp)
	{
		if (fscanf(fp, "nameserver %s\n", dnsname) != EOF)
		{
			fclose(fp);
			LOG_INFO("dns=%s", dnsname);
			return inet_addr(dnsname);
		}
		LOG_INFO("net_get_dns: scan fail!");
	}
	LOG_INFO("net_get_dns: file \"%s\" opened for reading error!", RESOLV_CONF);
	return INADDR_ANY;
}

/**
 * @brief	start dhcp
 * @param	"char *ifname" : [IN]interface name
 * @return	pid
 */
pid_t net_start_dhcpcd(char *ifname)
{
	pid_t pid;

	if ((pid = vfork()) == 0)
	{
		/* the child */
		execlp(DHCPC_EXEC_PATH, DHCPC_EXEC_PATH, ifname, NULL);
		LOG_ERROR("exec dhcpcd failed: %s", strerror(errno));
		_exit(0);
	}
	else if (pid < 0)
	{
		LOG_ERROR("fork dhcpcd failed: %s", strerror(errno));
		return -1;
	}
	return pid;
}

/**
 * @brief	renew dhcp.
 * @param	"pid_t pid" : pid
 * @retval	0 : success ; -1 : fail
 */
int net_renew_dhcpcd(pid_t pid)
{
	if (pid > 0)
	{
		if (kill(pid, SIGALRM) == 0)
			return 0;
		LOG_ERROR("net_disable_dhcpcd, kill error: %s", strerror(errno));
	}
	LOG_INFO("net_disable_dhcpcd, pid error");
	return -1;
}

/**
 * @brief	enable dhcp.
 * @param	none
 * @retval	none
 */
void net_enable_dhcpcd(void)
{
	system("killall -9 dhcpcd-eth0");
	system("rm /var/run/dhcpcd-eth0.pid;rm -rf /tmp/dhcpcd-eth0*\n");
	system("/opt/ipnc/dhcpcd/./dhcpcd-eth0&\n");
}

/**
 * @brief	disable dhcp.
 * @param	none
 * @retval	none
 */
void net_disable_dhcpcd(void)
{
	system("killall -9 dhcpcd-eth0");
	system("rm /var/run/dhcpcd-eth0.pid;rm -rf /tmp/dhcpcd-eth0*\n");
}

/**
 * @brief	search gateway
 * @param	"char *buf" : [IN]buffer
 * @param	"in_addr_t *gate_addr" : [OUT]gateway address
 * @return	0 : success ; -1 : fail
 */
int net_search_gateway(char *dev, char *buf, in_addr_t *gate_addr)
{
	char iface[16];
	unsigned long dest, gate;
	int iflags;

	sscanf(buf, "%s\t%08lX\t%08lX\t%8X\t", iface, &dest, &gate, &iflags);
	LOG_INFO("net_search_gateway:%s, %lX, %lX, %X", iface, dest, gate, iflags);
	if (((iflags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY)) && (strcmp(iface, dev) == 0))
	{
		*gate_addr = gate;
		return 0;
	}
	return -1;
}

/**
 * @brief	set gateway
 * @param	"in_addr_t addr" : [IN]gateway address
 * @return	0 : success ; -1 : fail
 */
int net_set_gateway(char *dev, in_addr_t addr)
{
	in_addr_t gate_addr;
	char buff[132];
	FILE *fp = fopen(PROCNET_ROUTE_PATH, "r");

	if (!fp)
	{
		LOG_ERROR("/proc/net/route： %s", strerror(errno));
		LOG_INFO("INET (IPv4) not configured in this system.");
		return -1;
	}
	fgets(buff, 130, fp);
	while (fgets(buff, 130, fp) != NULL)
	{
		if (net_search_gateway(dev, buff, &gate_addr) == 0)
		{
			net_del_gateway(dev, gate_addr);
		}
	}
	fclose(fp);

	return net_add_gateway(dev, addr);
}

int net_set_gateway_a(char *dev, char *addr)
{

	in_addr_t in_addr;

	if (dev == NULL || addr == NULL)
	{
		LOG_INFO("net_set_gateway_a() invalid arguments");
		return -1;
	}

	in_addr = inet_addr(addr);

	return net_set_gateway(dev, in_addr);
}

/**
 * @brief	clean gateway
 * @param	none
 * @return	0 : success ; -1 : fail
 */
int net_clean_gateway(char *dev)
{
	in_addr_t gate_addr;
	char buff[132];
	FILE *fp = fopen(PROCNET_ROUTE_PATH, "r");

	if (!fp)
	{
		LOG_ERROR("/proc/net/route： %s", strerror(errno));
		LOG_INFO("INET (IPv4) not configured in this system.");
		return -1;
	}
	fgets(buff, 130, fp);
	while (fgets(buff, 130, fp) != NULL)
	{
		if (net_search_gateway(dev, buff, &gate_addr) == 0)
		{
			net_del_gateway(dev, gate_addr);
		}
	}
	fclose(fp);

	return 0;
}

/**
 * @brief	get gateway
 * @param	none
 * @return	gatewat address
 */
in_addr_t net_get_gateway(char *dev)
{
	in_addr_t gate_addr;
	char buff[132];
	FILE *fp = fopen(PROCNET_ROUTE_PATH, "r");

	if (!fp)
	{
		LOG_ERROR("/proc/net/route： %s", strerror(errno));
		LOG_INFO("INET (IPv4) not configured in this system.");
		return (INADDR_ANY);
	}
	fgets(buff, 130, fp);
	while (fgets(buff, 130, fp) != NULL)
	{
		if (net_search_gateway(dev, buff, &gate_addr) == 0)
		{
			fclose(fp);
			return gate_addr;
		}
	}
	fclose(fp);
	return (INADDR_ANY);
}

int net_get_gateway_a(char *dev, char *addr)
{

	in_addr_t in_addr;
	char *pAddr = NULL;

	if (dev == NULL || addr == NULL)
	{
		LOG_INFO("net_get_gateway_a() invalid arguments");
		return -1;
	}

	in_addr = net_get_gateway(dev);
	pAddr = inet_ntoa(*(struct in_addr *)&in_addr);
	if (pAddr == NULL)
	{
		LOG_INFO("net_get_gateway_a() inet_ntoa() error");
		return -1;
	}
	strcpy(addr, pAddr);

	return 0;
}

/**
 * @brief	get net info
 * @param	"char *ifname" : [IN]interface name
 * @param	"struct NET_CONFIG *netcfg" : [OUT]net config
 * @return	0 : success ; -1 : fail
 */
int net_get_info(char *ifname, struct NET_CONFIG *netcfg)
{
	struct ifreq ifr;
	int skfd;
	struct sockaddr_in *saddr;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		LOG_ERROR("socket error： %s", strerror(errno));
		return -1;
	}

	saddr = (struct sockaddr_in *)&ifr.ifr_addr;
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0)
	{
		LOG_ERROR("net_get_info: ioctl SIOCGIFADDR： %s", strerror(errno));
		close(skfd);
		return -1;
	}
	netcfg->ifaddr = saddr->sin_addr.s_addr;
	LOG_INFO("ifaddr=0x%x", netcfg->ifaddr);

	if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0)
	{
		LOG_ERROR("net_get_info: ioctl SIOCGIFNETMASK： %s", strerror(errno));
		close(skfd);
		return -1;
	}
	netcfg->netmask = saddr->sin_addr.s_addr;
	LOG_INFO("netmask=0x%x", netcfg->netmask);

	if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
	{
		LOG_ERROR("net_get_info: ioctl SIOCGIFHWADDR： %s", strerror(errno));
		close(skfd);
		return -1;
	}
	memcpy(netcfg->mac, ifr.ifr_ifru.ifru_hwaddr.sa_data, IFHWADDRLEN);
	LOG_INFO("hwaddr=%02x:%02x:%02x:%02x:%02x:%02x", netcfg->mac[0], netcfg->mac[1],
			 netcfg->mac[2], netcfg->mac[3], netcfg->mac[4], netcfg->mac[5]);

	close(skfd);
	netcfg->gateway = net_get_gateway(ifname);
	LOG_INFO("gateway=0x%x", netcfg->gateway);
	netcfg->dns = net_get_dns();
	return 0;
}
/**
* @brief check ethernet status
*
* @param pInterface [I] ethernt device name. Ex: "eth0" "eth1"
* @return Link status
* @retval 0  Linkdown
* @retval 1  Linkup
* @retvl -1  Error
*/

#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <net/if.h>

#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
int Check_Link_status(const char *pIfName)
{
	int skfd;
	struct ifreq ifr;
	struct ethtool_value edata;
	edata.cmd = ETHTOOL_GLINK;
	edata.data = 0;
	memset(&ifr, 0, sizeof(ifr));
	strncpy(ifr.ifr_name, pIfName, sizeof(ifr.ifr_name) - 1);
	ifr.ifr_data = (char *)&edata;
	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) == 0)
		return -1;
	if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
	{
		close(skfd);
		return -1;
	}
	close(skfd);
	return edata.data;
}

/**
* @brief check ethernet speed
*
* @param pInterface [I] ethernt device name. Ex: "eth0" "eth1"
* @return Ethernet speed
* @retval 0  10M
* @reval 1  100M
* @retval -1  Error
*/
int Check_Link_speed(char *pInterface)
{
	int skfd = 0;
	struct ifreq ifr;
	struct mii_data *mii = NULL;

	if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		perror("socket");
		return -1;
	}

	bzero(&ifr, sizeof(ifr));
	strncpy(ifr.ifr_name, pInterface, IFNAMSIZ - 1);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0)
	{
		perror("ioctl");
		return -1;
	}

	mii = (struct mii_data *)&ifr.ifr_data;
	mii->reg_num = 0; //sPHY_register 0
	if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0)
	{
		perror("ioctl2");
		return -1;
	}
	close(skfd);
	if (mii->val_out & (1 << 13)) //scheck bit13 of PHY_REG0
	{
		//LOG_INFO( "100M" );
		return 1;
	}
	else
	{
		//LOG_INFO( "10M" );
		return 0;
	}
}

/**
 * @brief	main entry
 * @param	command line argument
 * @return	error code
 */
//#define NET_TEST
#ifdef NET_TEST
int main(int argc, char **argv)
{
	struct NET_CONFIG netcfg;
	int i;

	if (argc < 3)
	{
		net_get_info("eth0", &netcfg);
		return 0;
	}

	for (i = 1; i < argc; i++)
		LOG_INFO("arg[%d]=%s", i, argv[i]);

	if (!strcmp(argv[2], "up"))
		net_set_flag(argv[1], (IFF_UP | IFF_RUNNING));
	else if (!strcmp(argv[2], "down"))
		net_clr_flag(argv[1], IFF_UP);
	else if (!strcmp(argv[2], "ip"))
	{
		net_set_ifaddr(argv[1], inet_addr(argv[3]));
	}
	else if (!strcmp(argv[2], "netmask"))
	{
		net_set_netmask(argv[1], inet_addr(argv[3]));
	}
	else if (!strcmp(argv[2], "gateway"))
	{
		if (!strcmp(argv[1], "add"))
			net_add_gateway(inet_addr(argv[3]));
		else
			net_del_gateway(inet_addr(argv[3]));
	}
	else if (!strcmp(argv[2], "dhcpcd"))
	{
		if (!strcmp(argv[3], "enable"))
			net_enable_dhcpcd(argv[1]);
		else
			net_disable_dhcpcd(argv[1]);
	}
	else if (!strcmp(argv[1], "dns"))
		net_set_dns(argv[2]);
	else
		LOG_INFO("unknown argument!");
	return 0;
}
#endif
